//
//  tdl/utils/cmd_arg.h
//  Created by tommywang on 13-4-22.
//

#ifndef tdl_utils_cmdarg_h
#define tdl_utils_cmdarg_h
extern "C" {
#include <getopt.h>
} // extern "C"
#include <map>
#include <vector>
using namespace std;

namespace tdl {
///////////////
struct cmd_arg
{
	std::string		long_name;
	bool			has_arg;
	char			short_name;
public:
	explicit cmd_arg(const std::string& ln, bool arg, char sn) : long_name(ln), has_arg(arg), short_name(sn) {}
};

std::map<char, std::string> parse_cmd_args(const std::vector<cmd_arg>& vo, int argc, char* argv[])
{
/*
	const char* short_options = "hdc:";
	const struct option long_options[] = {
		{ "help", 0, NULL, 'h' },
		{ "daemon", 0, NULL, 'd' },
		{ "config", 1, NULL, 'c' },
		{ NULL, 0, NULL, 0 } // Required at end of array
	};
*/
	uint32_t nopt = vo.size();
	std::string short_options;
	std::vector<int> arg_options;
	struct option* long_options = new struct option[nopt + 1];
	for(uint32_t i = 0; i < nopt; ++i)
	{
		short_options += vo[i].short_name;
		if(vo[i].has_arg)
		{
			short_options += ":";
			arg_options.push_back(vo[i].short_name);
		}

		long_options[i].name = vo[i].long_name.c_str();
		long_options[i].has_arg = vo[i].has_arg ? 1 : 0;
		long_options[i].flag = NULL;
		long_options[i].val = vo[i].short_name;
	}
	long_options[nopt].name = NULL;
	long_options[nopt].has_arg = 0;
	long_options[nopt].flag = NULL;
	long_options[nopt].val = 0;

	std::map<char, std::string> r;
	while(1)
	{
		int next_option = ::getopt_long(argc, argv, short_options.c_str(), long_options, NULL);
		if(next_option == -1)
			break;

		std::vector<int>::iterator it = ::find(arg_options.begin(), arg_options.end(), next_option);

		if(it == arg_options.end())
			r.insert(make_pair(next_option, string("")));
		else
			r.insert(make_pair(next_option, string(optarg)));

	}

	delete[] long_options;

	return r;
}

/////////////
}	// namespace tdl

#endif

